import { FeatherChevronDown } from "cui-vue-icons/feather";
import Tree, { NodeKeyType, TreeCheckMod, TreeInstanceProps, TreeNode, TreeProps } from "../../Tree";
import { computed, defineComponent, PropType, ref, watch } from "vue";
import Dropdown from "../../Dropdown";
import { Value } from "../../inner/Value";
import { TagConfig } from "../../TagGroup";
import formFieldRef from "../../use/formFieldRef";

export interface TreeSelectProps extends TreeProps {
    data: TreeNode[],
    transfer?: boolean,
    align?: 'bottomLeft'|'bottomRight',
    disabled?: boolean,
    clearable?: boolean,
    prepend?: any,
    mode?: TreeCheckMod,
    size?: 'small'|'large',
    showMax?: number,
    valueClosable?: boolean,
    placeholder?: string,
    showMore?: boolean
    multi?: boolean,
    asFormField?: boolean
    onChange?: (value: NodeKeyType|NodeKeyType[]) => void,
}

export default defineComponent({
    name: 'TreeSelect',
    props: {
        transfer: { type: Boolean as PropType<TreeSelectProps['transfer']>, default: false},
        align: { type: String as PropType<TreeSelectProps['align']>},
        disabled: { type: Boolean as PropType<TreeSelectProps['disabled']>},
        clearable: { type: Boolean as PropType<TreeSelectProps['clearable']> },
        prepend: { type: [Object, Number, String] as PropType<TreeSelectProps['prepend']>},
        mode: { type: String as PropType<TreeSelectProps['mode']>},
        size: { type: String as PropType<TreeSelectProps['size']>},
        showMax: { type: Number as PropType<TreeSelectProps['showMax']>},
        valueClosable: { type: Boolean as PropType<TreeSelectProps['valueClosable']>},
        placeholder: { type: String as PropType<TreeSelectProps['placeholder']>},
        showMore: { type: Boolean as PropType<TreeSelectProps['showMore']>},
        multi: { type: Boolean as PropType<TreeSelectProps['multi']>},
        asFormField: { type: Boolean as PropType<TreeSelectProps['asFormField']>, default: true },
        emptyText: {type: String as PropType<TreeProps['emptyText']>, default: '暂无数据'},
        data: {type: Array as PropType<TreeProps['data']>, default: () => []},
        checkable: {type: Boolean as PropType<TreeProps['checkable']>, default: false},
        checkRelation: {type: String as PropType<TreeProps['checkRelation']>, default: 'related'},
        directory: {type: Boolean as PropType<TreeProps['directory']>, default: false},
        contextMenu: {type: Object as PropType<TreeProps['contextMenu']>},
        draggable: {type: Boolean as PropType<TreeProps['draggable']>, default: false},
        loadData: {type: Function as PropType<TreeProps['loadData']>},
        beforeDropMethod: {type: Function as PropType<TreeProps['beforeDropMethod']>},
        beforeExpand: {type: Function as PropType<TreeProps['beforeExpand']>},
        onNodeDragStart: {type: Function as PropType<TreeProps['onNodeDragStart']>},
        onNodeDragEnter: {type: Function as PropType<TreeProps['onNodeDragEnter']>},
        onNodeDragOver: {type: Function as PropType<TreeProps['onNodeDragOver']>},
        onNodeDragLeave: {type: Function as PropType<TreeProps['onNodeDragLeave']>},
        onSelectMenu: {type: Function as PropType<TreeProps['onSelectMenu']>},
        onChange: {type: Function as PropType<TreeProps['onChange']>},
        onContextMenu: {type: Function as PropType<TreeProps['onContextMenu']>},
        modelValue: {type: Array as PropType<TreeProps['modelValue']>},
        keyField: {type: String as PropType<TreeProps['keyField']>},
        titleField: {type: String as PropType<TreeProps['titleField']>},
        selectedClass: {type: String as PropType<TreeProps['selectedClass']>},
        draggingClass: {type: String as PropType<TreeProps['draggingClass']>},
        customIcon: {type: Function as PropType<TreeProps['customIcon']>},
        arrowIcon: {type: Function as PropType<TreeProps['arrowIcon']>},
    },
    emits: ['nodeSelect', 'nodeExpand', 'nodeCollapse', 'nodeChecked', 'change',
        'update:modelValue', 'nodeDrop'],
    setup (props, {emit, expose}) {
        // 状态管理
        const innerValue = formFieldRef<NodeKeyType | NodeKeyType[]>(props, emit, props.multi ? [] : '');
        const text = ref<any>('');
        const treeRef = ref<TreeInstanceProps>();
        const align = computed(() => props.align ?? 'bottomLeft');
        const mode = computed(() => props.mode ?? TreeCheckMod.HALF);
        const checkRelation = computed(() => props.checkRelation ?? 'related');

        // 类名处理
        const classList = computed(() => ({
            'cm-tree-select': true,
            'cm-tree-select-disabled': props.disabled,
            [`cm-tree-select-${props.size}`]: props.size,
        }));

        // 事件处理
        const onSelect = (data: TreeNode) => {
            if (!props.multi) {
                innerValue.value = data[props.keyField || 'id'];
                emit('change', data[props.keyField || 'id']);
            }
        };

        const onTreeChange = (ids: NodeKeyType[] | NodeKeyType) => {
            innerValue.value = ids;
            emit('change', ids);
        };

        const onClear = () => {
            innerValue.value = props.multi ? [] : '';
            emit('change', innerValue.value);
        };

        const onValueClose = (item: TagConfig) => {
            if (Array.isArray(innerValue.value)) {
                const newValue = innerValue.value.filter(v => v !== item.id);
                innerValue.value = newValue;
            }
        };

        // 获取选中状态
        const getChecked = () => {
            return treeRef.value?.getCheckedKeys(mode.value) || [];
        };

        // 值变化监听
        watch(innerValue, (newVal, oldVal) => {
            updateText();
        });

        // 更新显示文本
        const updateText = () => {
            if (props.multi) {
                const all = treeRef.value?.getChecked(mode.value).map(item => ({
                    id: item[props.keyField || 'id'],
                    title: item[props.titleField || 'title']
                })) || [];
                text.value = all;
            } else {
                const data = treeRef.value?.getNode(innerValue.value as NodeKeyType);
                text.value = data?.[props.titleField || 'title'] || '';
            }
        };

        // 数据变化监听
        watch(() => props.data, () => {
            setTimeout(updateText);
        });

        // 暴露组件方法
        expose({
            getChecked,
            clear: onClear
        });

        return () => (
            <div class={classList.value} tabindex="1">
                <Dropdown
                    transfer={props.transfer}
                    fixWidth
                    align={align.value}
                    disabled={props.disabled}
                    trigger="click"
                    menu={
                        <div class="cm-tree-select-wrap">
                            <Tree
                                data={props.data}
                                checkable={props.multi}
                                onNodeSelect={onSelect}
                                onChange={onTreeChange}
                                ref={treeRef}
                                modelValue={props.multi ? innerValue.value as NodeKeyType[] : undefined}
                                selected={!props.multi ? innerValue.value as NodeKeyType : undefined}
                                checkRelation={checkRelation.value}
                            />
                        </div>
                    }
                >
                    <Value
                        text={text.value}
                        multi={props.multi}
                        showMax={props.showMax}
                        disabled={props.disabled}
                        showMore={props.showMore}
                        valueClosable={props.valueClosable}
                        clearable={props.clearable}
                        onClear={onClear}
                        prepend={props.prepend}
                        size={props.size}
                        icon={<FeatherChevronDown />}
                        onClose={onValueClose}
                    />
                </Dropdown>
            </div>
        );
    }
});
